package com.zhny.aiot.control.cabinet.plugin;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import com.zhny.aiot.control.cabinet.plugin.factory.ControlCabinetFactoryBuild;
import com.zhny.aiot.control.cabinet.plugin.model.AdjustableParam;
import com.zhny.aiot.control.cabinet.plugin.model.CommandParam;
import com.zhny.aiot.control.cabinet.plugin.model.ControlCabinetStoreEntry;
import com.zhny.aiot.plugin.ICenterFacilities;
import com.zhny.aiot.plugin.IDeviceFactory;
import com.zhny.aiot.plugin.core.model.IRequestMessage;
import com.zhny.aiot.plugin.core.utils.MessageUtils;
import com.zhny.aiot.plugin.modbus.ModemEngine;
import com.zhny.aiot.plugin.modbus.device.ModemConfig;
import com.zhny.aiot.plugin.modbus.device.ModemDevice;
import com.zhny.aiot.plugin.modbus.handler.model.ModemMultiRegisterRequestMessage;
import com.zhny.aiot.plugin.modbus.handler.model.ModemRequestMessage;
import com.zhny.aiot.plugin.modbus.handler.model.ModemResponseMessage;
import com.zhny.aiot.plugin.model.DeviceEntity;
import com.zhny.aiot.plugin.model.MessageEntry;
import com.zhny.aiot.plugin.model.MessageType;
import com.zhny.aiot.plugin.model.TaskEntity;
import org.pf4j.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Map;

public class ControlCabinetDevice extends ModemDevice<ControlCabinetStoreEntry> {
    private static final Logger logger = LoggerFactory.getLogger(ControlCabinetDevice.class);
    private final Map<String, CommandParam> CommandOperations;
    public ControlCabinetDevice(ModemEngine engine, IDeviceFactory<ModemConfig> factory, ICenterFacilities centerFacilities, DeviceEntity entity) {
        super (engine, factory, centerFacilities,entity);
        CommandOperations =  new ImmutableMap.Builder<String, CommandParam>()
                .put("openValve1", CommandParam.valueOf((short)5,0,65280))
                .put("closeValve1", CommandParam.valueOf((short)5,1,65280))
                .put("openValve2", CommandParam.valueOf((short)5,2,65280))
                .put("closeValve2", CommandParam.valueOf((short)5,3,65280))
                .put("powerSupply", CommandParam.valueOf((short)5,4,65280))
                .put("powerFailure", CommandParam.valueOf((short)5,4,0))
                .put("queryValveStatus", CommandParam.valueOf((short)2,0,4))
                .put("queryStatus", CommandParam.valueOf((short)2,0,4))
                .put("queryFlow", CommandParam.valueOf((short)3,200,44))
                .put("setAdValve1", CommandParam.valueOf((short)16,20,0))
                .put("setAdValve2", CommandParam.valueOf((short)16,22,0))
                .put("queryPreAndAdValve", CommandParam.valueOf((short)3,50,16)).build();
    }

    @Override
    public void onDecoder(ModemResponseMessage modemResponseMessage) {
        MessageEntry entry = MessageUtils.createMessageEntry (this.getId ());
        entry.setType (MessageType.RESULT);
        entry.getProperties ().put ("gprs",((ModemConfig)this.getConfig ()).getGprsNo ());
        entry.getProperties ().put ("address",((ModemConfig)this.getConfig ()).getAddress ());

        ControlCabinetStoreEntry storeEntry = new ControlCabinetFactoryBuild()
                .setResponseMessage(modemResponseMessage)
                .build(this);
        if(storeEntry == null){
            entry.setType(MessageType.ERROR);
        }else {
            logger.info("zhny cabinet device [{}] response message decode success !",this.getConfigKey());
            entry.setData(storeEntry);
        }
        this.nofity(entry);
    }

    @Override
    protected IRequestMessage getCommand(TaskEntity taskEntity) {
        MessageEntry entry= MessageUtils.createMessageEntry(this.getId ());
        entry.getProperties().put("task_name", taskEntity.getMethodName ());
        entry.setType (MessageType.OPERATION);
        CommandParam command = CommandOperations.get (taskEntity.getMethodName ());
        if(command == null){
            entry.setType (MessageType.ERROR);
            entry.setData (String.format("factory[%s] no support command [%s]",getTypeId (),taskEntity.getMethodName ()));
            this.nofity (entry);
            return null;
        }else{
            if(!StringUtils.isNullOrEmpty(taskEntity.getParams())){
                AdjustableParam param = getParamObject(taskEntity.getParams());
                command.setDataSize(param.getValue());
                return new ModemMultiRegisterRequestMessage(
                        Integer.valueOf(this.getConfig().getAddress()),
                        command.getOper(),
                        command.getRegAdress(),
                        Float.valueOf((float)command.getDataSize())
                );
            }
            else {
                return new ModemRequestMessage(
                        Integer.valueOf(this.getConfig().getAddress()),
                        command.getOper(),
                        command.getRegAdress(),
                        command.getDataSize()
                );
            }
        }
    }

    private AdjustableParam getParamObject(String paramJson){
        AdjustableParam param = null;
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        try{
            param = mapper.readValue (paramJson,AdjustableParam.class);
        }catch (Exception e){
            logger.error ("Parse param error !");
            return  null;
        }
        return param;
    }

    @Override
    protected void disposable() {

    }
}
